using UnityEngine;
using System.Collections;

public class BM_MessageManager : MonoBehaviour
{
	public enum SendType
	{
		SEND_TOONE
	,	SEND_TOALL
	,	SEND_TOALLBUTME
	}
	
	private struct MessageInfo
	{
		public BM_MessageHandler	m_rTarget;
		public BM_BaseMessage		m_rMessage;
		public SendType				m_eSendType;
		
		public MessageInfo(BM_MessageHandler rTarget, BM_BaseMessage rMessage, SendType	eSendType)
		{
			m_rTarget = rTarget;
			m_rMessage = rMessage;
			m_eSendType = eSendType;
		}
	}
	
	#region Members
	
	private uint				m_uIdGenerator = 0;

	private static readonly int	m_iQueueCapacity		= 30;
	private Queue				m_vMessageQueue = null;
	
	private static readonly int	m_iListCapacity		= 200;
	private ArrayList			m_vHandlers = null;
	
	#endregion

	
	#region Singleton
	
	private static BM_MessageManager		m_rManagerReference = null;
	
	public static BM_MessageManager Instance()
	{
		if(m_rManagerReference == null)
		{
			Debug.LogError("SV_MessageManager.Instance() -> Manager non inizializzato! ERRORE!");
			Debug.DebugBreak();
		}
		
		return m_rManagerReference;
	}
	
	#endregion
	
	
	public void Awake()
	{
		m_rManagerReference = this;
		
		m_vMessageQueue = new Queue(m_iQueueCapacity);
		m_vHandlers = new ArrayList(m_iListCapacity);
	}
	
	public void Start() { }
	
	public void OnDestroy()
	{
		m_rManagerReference = null;
	}

	public void Update()
	{
		if(m_vHandlers != null && m_vMessageQueue != null)
		{
			// ordino a tutti i listener (anche quelli da rimuovere) di pulire la propria coda dei messaggi ricevuti
			foreach(BM_MessageHandler rListener in m_vHandlers)
				rListener.CleanMessages();
			
			// a questo punto posso eseguire il dispatch dei messaggi
			while(m_vMessageQueue.Count > 0)
			{
				MessageInfo currentMessage = (MessageInfo)m_vMessageQueue.Dequeue();
				switch(currentMessage.m_eSendType)
				{
				case SendType.SEND_TOONE:
					if(currentMessage.m_rTarget != null)
						currentMessage.m_rTarget.ReceiveMessage(currentMessage.m_rMessage);
					break;
					
				case SendType.SEND_TOALL:
					foreach(BM_MessageHandler rListener in m_vHandlers)
						rListener.ReceiveMessage(currentMessage.m_rMessage);
					break;
					
				case SendType.SEND_TOALLBUTME:
					
					if(currentMessage.m_rMessage.m_rSender != null )
					{
						foreach(BM_MessageHandler rListener in m_vHandlers)
						{
							if(currentMessage.m_rMessage.m_rSender.Id != rListener.Id)
								rListener.ReceiveMessage(currentMessage.m_rMessage);
						}
					}
					else
					{
						Debug.LogError("SV_MessageManager.Update() -> Il mittente è null!");
						Debug.DebugBreak();
					}
						
					break;
					
				default:
					break;
				}
			}
			m_vMessageQueue.Clear(); // ridondante, ma per sicurezza...
		}
		else
		{
			Debug.LogError("SV_MessageManager.Update() -> la coda o la lista degli handler non sono inizializzate!");
			Debug.DebugBreak();
		}
	}
	
	public void AddListener(BM_MessageHandler rListener)
	{
		if(m_vHandlers != null)
		{
			m_vHandlers.Add(rListener);
			rListener.Id = m_uIdGenerator;
			++m_uIdGenerator;
		}
		else
		{
			Debug.LogError("SV_MessageManager.Update() -> la lista degli handler è inizializzata!");
			Debug.DebugBreak();
		}
	}
	
	public void RemoveListener(BM_MessageHandler rListener)
	{
		if(m_vHandlers != null)
			m_vHandlers.Remove(rListener);
		else
		{
			Debug.LogError("SV_MessageManager.Update() -> la lista degli handler è inizializzata!");
			Debug.DebugBreak();
		}
	}
	
	public void RequestSendMessage(BM_MessageHandler rTarget, BM_BaseMessage rMessage, SendType eSendType)
	{
		if(m_vMessageQueue != null)
			m_vMessageQueue.Enqueue(new MessageInfo(rTarget, rMessage, eSendType));
		else
		{
			Debug.LogError("SV_MessageManager.Update() -> la coda dei messaggi non è inizializzata!");
			Debug.DebugBreak();
		}
	}
}
